﻿using System.Text;
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using UC_Framework;

#pragma warning disable 1591 // sadly not yet commented

namespace UC_Framework
{
    /// <summary>
    /// GUI parent class 
    /// </summary>
    public class GUI_Control : UC_Renderable
    {
        public Rectangle bounds;
        public bool visible;
        public List<GUI_Control> controls;
        //public Color colour;
        public bool focus; // does this control have focus
        public GUI_Control parent; // my parent control or null;

        //public override bool MouseMoveEvent(MouseState ms, MouseState previousMs) { return false; }
        //public override bool MouseDownEventLeft(float mouse_x, float mouse_y) { return false; }
        //public override bool MouseUpEventLeft(float mouse_x, float mouse_y) { return false; }
        //public override bool MouseDownEventRight(float mouse_x, float mouse_y) { return false; }
        //public override bool MouseUpEventRight(float mouse_x, float mouse_y) { return false; }
        //public override bool KeyHitEvent(Keys keyHit) { return false; }


        public virtual void drawSubControls(SpriteBatch sb)
        {
            if (controls.Count <= 0) return;

            for (int i = 0; i < controls.Count; i++)
            {
                if (controls[i].visible) controls[i].Draw(sb);
            }
        }

        protected void init()
        {
            bounds = new Rectangle(0, 0, 100, 10);
            visible = true;
            controls = new List<GUI_Control>();
            colour = Color.White;
            parent = null;
            focus = false;
        }

        public void Clear()
        {
            controls.Clear();
        }

        public void AddControl(GUI_Control c)
        {
            controls.Add(c);
            c.parent = this;
        }

        public GUI_Control getControl(int cnum)
        {
            return controls[cnum];
        }

        /// <summary>
        /// Return a boolean that is true if the point is inside the bounds
        /// and the control is visible
        /// </summary>
        public Boolean inside(float x, float y)
        {
            if (!visible) return false;
            Vector2 v = getPos();
            Rectangle temp = new Rectangle((int)v.X, (int)v.Y, bounds.Width, bounds.Height);
            if (x < temp.Left) return false;
            if (y < temp.Top) return false;
            if (x > temp.Right) return false;
            if (y > temp.Bottom) return false;
            return true;
        }

        public void clearFocus(bool clearParent)
        {
            focus = false;
            if (controls.Count <= 0) return;

            for (int i = 0; i < controls.Count; i++)
            {
                controls[i].clearFocus(false);
            }
            if (clearParent && parent != null) parent.clearFocus(true);

        }

        public Vector2 getPos()
        {
            if (parent == null)
            {
                return new Vector2(bounds.X, bounds.Y);
            }
            else
            {
                return new Vector2(bounds.X, bounds.Y) + parent.getPos();
            }
        }

        public void setWidthHeight(int w, int h)
        {
            bounds.Width = w;
            bounds.Height = h;
        }

        public bool passOnKeyhit(Keys keyHit)
        {
            if (controls.Count <= 0) return false;

            for (int i = 0; i < controls.Count; i++)
            {
                bool rc = controls[i].KeyHitEvent(keyHit);
                if (rc) return true;
            }
            return false;
        }

        public void setColor(Color c, bool passOn)
        {
            colour = c;
            if (passOn)
            {
                for (int i = 0; i < controls.Count; i++)
                {
                    controls[i].colour = c;
                }
            }
        }

        public void setPos(float x, float y)
        {
            bounds.X = (int)x;
            bounds.Y = (int)y;
        }
    }


    /// <summary>
    /// Simple Gui class with 2 frames 
    /// </summary>
    public class Button : GUI_Control
    {
        Texture2D up;
        Texture2D down;
        public int state; // 0=up 1=down
        public bool wasClicked; 

        public Button(Texture2D upZ, Texture2D downZ, Vector2 pos)
        {
            init();
            up = upZ;
            down = downZ;
            bounds = new Rectangle((int)pos.X,(int)pos.Y,up.Width,up.Height);
            wasClicked = false;
        }
        
        public override void Draw(SpriteBatch sb)
        {
            if(!visible)return;
            Vector2 pos = getPos();
            Rectangle r = new Rectangle((int)pos.X, (int)pos.Y, bounds.Width, bounds.Height);
            if (state == 0)
                sb.Draw(up, r, colour);
            if (state == 1)
                sb.Draw(down, r, colour);
        drawSubControls(sb);
        }

        public override bool MouseDownEventLeft(float mouse_x, float mouse_y)
        {
            // note a button is unlikey to have children so its considered a terminal node
            if (inside(mouse_x, mouse_y))
            {
                wasClicked = true;
                return true;
            }
            return false;
        }
    }

    public class TextBox : GUI_Control
    {
        Texture2D tex;
        SpriteFont font;
        public string text;
        public Vector2 textOffset;

        public TextBox(Texture2D texZ, Vector2 pos, SpriteFont fonty, string s)
        {
            init();
            font = fonty;
            tex = texZ;
            bounds = new Rectangle((int)pos.X, (int)pos.Y, tex.Width, tex.Height);
            text = s;
            textOffset = new Vector2(5, 3);
        }

        public override void Draw(SpriteBatch sb)
        {
            if(!visible)return;
            Vector2 pos = getPos();
            Rectangle r = new Rectangle((int)pos.X, (int)pos.Y, bounds.Width, bounds.Height);
            sb.Draw(tex, r, colour);
            if (text != "") sb.DrawString(font, text, new Vector2(pos.X + textOffset.X, pos.Y + textOffset.Y), colour);
            drawSubControls(sb);
        }

        public override bool MouseDownEventLeft(float mouse_x, float mouse_y)
        {
            if (inside(mouse_x, mouse_y))
            {
                if (controls.Count > 0)
                {
                    // hand to my children controls
                    for (int i = 0; i < controls.Count; i++)
                    {
                        bool rc = controls[i].MouseDownEventLeft(mouse_x, mouse_y);
                        if (rc) return true;
                    }
                }
            }
            return false;
         }

        public override void Update(GameTime gameTime)
        {
                if (controls.Count > 0)
                {
                    // hand to my children controls
                    for (int i = 0; i < controls.Count; i++)
                    {
                        controls[i].Update(gameTime);
                    }
                }

        }

        public override bool KeyHitEvent(Keys keyHit)
        {
            return passOnKeyhit(keyHit);
        }
    }

    public class InputBox : GUI_Control
    {
        Texture2D tex;
        SpriteFont font;
        public string text;
        int maxLength;
        int ticks;
        public Vector2 textOffset;
        
        public InputBox(Texture2D texZ, Vector2 pos, SpriteFont fonty, string s, int maxLen)
        {
            init();
            font = fonty;
            tex = texZ;
            bounds = new Rectangle((int)pos.X, (int)pos.Y, tex.Width, tex.Height);
            text = s;
            ticks = 0;
            textOffset = new Vector2(7, 5);
            maxLength = maxLen;
        }

        public override void Draw(SpriteBatch sb)
        {
            if (!visible) return;
            Vector2 pos = getPos();
            Rectangle r = new Rectangle((int)pos.X, (int)pos.Y, bounds.Width, bounds.Height);
            sb.Draw(tex, r, colour);
            if ((ticks / 20) % 2 == 0 && focus)
            {
                sb.DrawString(font, text + "|", new Vector2(pos.X + textOffset.X, pos.Y + textOffset.Y), colour);
            }
            else
            {
                sb.DrawString(font, text, new Vector2(pos.X + textOffset.X, pos.Y + textOffset.Y), colour);
            }
            drawSubControls(sb);
        }

        public override void Update(GameTime gameTime) 
        {
            ticks++;
        }

        public override bool KeyHitEvent(Keys key)
        {
            if (!focus) return false; 
            if (!visible) return false;
            
            if (key == Keys.Back && text.Length > 0) // Process Backspace
            {
                text = text.Remove(text.Length - 1, 1);
                return true;
            }

            if (key == Keys.Space)
            {
                text = text + " "; // we may need to process more keys seperately eg ;            
                return true;
            }

            if (key == Keys.Enter)
            {
                return true; // return was pressed
            }                    
              
            if (text.Length < maxLength) text = text + key.ToString();
            return true; 
        }

        public override bool MouseDownEventLeft(float mouse_x, float mouse_y)
        {
            if (inside(mouse_x, mouse_y))
            {
                if (controls.Count > 0)
                {
                    // hand to my children controls
                    for (int i = 0; i < controls.Count; i++)
                    {
                        bool rc = controls[i].MouseDownEventLeft(mouse_x, mouse_y);
                        if (rc) return true;
                    }
                }
                parent.clearFocus(true);
                focus = true;
                return true;
            }
            return false;
        }

    }
    
}
